//#include<bits/stdc++.h>
//using namespace std;
////#define int long long
//inline int read()
//{
//	// 快读；
//	int x = 0, f = 1;
//	char c = getchar();
//	while (c < '0' || c > '9') {
//		if (c == '-') {
//			f = -1;
//			c = getchar();
//		}
//	}
//	while (c >= '0' && c <= '9') {
//		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
//	}
//	return x * f;
//}
//const int inf = 123456789, maxn = 5005, maxm = 200005;
//struct edge {
//	int v, w, next;
//} e[maxm << 1];
////双向图
//int head[maxn], dis[maxn], cnt, n, m, tot, now = 1, ans;
//bool vis[maxn];
//inline void add(int u, int v, int w)
//{
//	e[++cnt].v = v;
//	e[cnt].w =  w;
//	e[cnt].next = head[u];
//	head[u] = cnt;
//}
//inline void init()
//{
//	n = read(), m = read();
//	for (int i = 1, u, v, w; i <= m; i++) {
//		u = read(), v = read(), w = read();
//		add(u, v, w), add(v, u, w);
//	}
//}
//inline int prim()
//{
//	// dis设为无穷
//	for (int i = 2; i <= n; i++) dis[i] = inf;
//	for (int i = head[1]; i; i = e[i].next) {
//		dis[e[i].v] = min(dis[e[i].v], e[i].w); //注意重边
//	}
//	while (++tot < n) {
//		int minn = inf;// min 设置为最大值
//		vis[now] = 1;//设置为已经走过哦
//		for (int i = 1; i <= n; i++) {
//			if (!vis[i] && minn > dis[i]) {
//				minn = dis[i];
//				now = i;
//			}
//		}
//		ans += minn;
//		for (int i = head[now]; i; i = e[i].next) {
//			int v = e[i].v;
//			if (dis[v] > e[i].w && !vis[v]) {
//				dis[v] = e[i].w;//更新dis 数组
//			}
//		}
//		return ans;
//	}
//}
//signed main()
//{
//	init();
//	printf("%d",prim());
//	return 0;
//}
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Edge {
	int u, v, weight;
};

bool compareEdges(const Edge& edge1, const Edge& edge2) {
	return edge1.weight < edge2.weight;
}

int findParent(vector<int>& parent, int node) {
	if (parent[node] == node)
		return node;
	return findParent(parent, parent[node]);
}

void unionSets(vector<int>& parent, int x, int y) {
	int parentX = findParent(parent, x);
	int parentY = findParent(parent, y);
	parent[parentY] = parentX;
}

int kruskalMST(vector<Edge>& edges, int numNodes) {
	sort(edges.begin(), edges.end(), compareEdges);
	
	vector<int> parent(numNodes + 1);
	for (int i = 1; i <= numNodes; i++)
		parent[i] = i;
	
	int mstWeight = 0, mstEdges = 0;
	for (auto edge : edges) {
		int parentU = findParent(parent, edge.u);
		int parentV = findParent(parent, edge.v);
		
		if (parentU != parentV) {
			unionSets(parent, edge.u, edge.v);
			mstWeight += edge.weight;
			mstEdges++;
		}
		
		if (mstEdges == numNodes - 1)
			break;
	}
	
	if (mstEdges != numNodes - 1)
		return -1; // Graph is not connected
	
	return mstWeight;
}

int main() {
	int N, M;
	cin >> N >> M;
	
	vector<Edge> edges(M);
	for (int i = 0; i < M; i++) {
		cin >> edges[i].u >> edges[i].v >> edges[i].weight;
	}
	
	int result = kruskalMST(edges, N);
	if (result == -1)
		cout << "orz" << endl;
	else
		cout << result << endl;
	
	return 0;
}
